/*
 * Copyright (c) 2012 Aleksander Zotov, Benedikt Markt, Aliaksei Babkovich
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 *  of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *  
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 *  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 *  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 *  THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package simulation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import user.UserManager;
import utils.ApplicationPreferences;
import utils.UserNotFoundException;
import database.DatabaseManager;

/**
 * This class manages all stored simulations and provides tools to start, cancel
 * and delete simulations
 * 
 * @author Benedikt Markt
 * @see DatabaseManager
 * @see Simulation
 */
public class SimulationManager {

	private static SimulationManager instance = new SimulationManager();

	private ArrayList<Simulation> simulations = new ArrayList<Simulation>();
	private ExecutorService executor;

	private SimulationManager() {
		DatabaseManager dbMan = new DatabaseManager();
		simulations = dbMan.loadSimulations();

		executor = Executors.newScheduledThreadPool(ApplicationPreferences
				.getInstance().getMaxConcurrentSims());
	}

	public static SimulationManager getInstance() {
		return instance;
	}

	public void reload() {
		DatabaseManager dbMan = new DatabaseManager();
		simulations.clear();
		simulations = dbMan.loadSimulations();
		executor = Executors.newScheduledThreadPool(ApplicationPreferences
				.getInstance().getMaxConcurrentSims());
	}
	
	/**
	 * Starts a new simulation
	 * 
	 * @param simulation
	 * @throws IOException
	 */
	public void startNewSimulation(Simulation simulation) throws IOException {

		SimulationRunner simRunner = new SimulationRunner(simulation);
		simRunner.setInterface(simulation);

		simulation.setProcess(executor.submit(simRunner));

		simulations.add(simulation);
		DatabaseManager dbMan = new DatabaseManager();
		dbMan.storeSimulation(simulation);

	}

	/**
	 * Deletes a simulation and cancels it if running
	 * 
	 * @param identifier
	 *            the unique id of the simulation to cancel
	 */
	public void deleteSimulation(String identifier) {
		Simulation sim = getSimulationByID(identifier);
		if (sim.getProcess() != null) {
			if (!sim.getProcess().isDone()) {
				sim.getProcess().cancel(true);
				UserManager userMan = UserManager.getInstance();
				try {
					userMan.getUser(sim.getUsername()).setRunningSim(false);
				} catch (UserNotFoundException e) {
				}
			}
		}
		simulations.remove(sim);
		DatabaseManager dbMan = new DatabaseManager();
		dbMan.deleteSimulation(identifier);
	}

	public ArrayList<Simulation> getSimulations() {
		return simulations;
	}

	/**
	 * @param identifier
	 *            the unique id of the simulation
	 * @return the corresponding simulation object
	 */
	public Simulation getSimulationByID(String identifier) {
		for (Simulation s : simulations) {
			if (s.getIdentifier().equals(identifier)) {
				return s;
			}
		}
		return null;
	}
}
